package client

import (
	"context"
	"fmt"
	"net"
	"sync"
	"sync/atomic"
	"time"
	
	"inkjet168x-sdk-go/sdk/protocol/common"
	"inkjet168x-sdk-go/sdk/protocol/text"
	"inkjet168x-sdk-go/sdk/protocol/barcode"
)

// HardwareClientConfig 硬件客户端配置
type HardwareClientConfig struct {
	// 网络配置
	ServerAddr    string        // 服务器地址 (IP:Port)
	LocalAddr     string        // 本地绑定地址 (可选)
	Timeout       time.Duration // 操作超时时间
	RetryCount    int           // 重试次数
	RetryInterval time.Duration // 重试间隔
	
	// 协议配置
	AutoSequence     bool                      // 是否自动管理序列号
	ProtocolFactory  common.ProtocolFactory    // 协议工厂
	
	// 连接池配置
	MaxConnections   int           // 最大连接数
	ConnectionTTL    time.Duration // 连接生存时间
	KeepAlive        bool          // 是否保持连接
}

// DefaultHardwareConfig 返回默认配置
func DefaultHardwareConfig(serverAddr string) *HardwareClientConfig {
	return &HardwareClientConfig{
		ServerAddr:       serverAddr,
		LocalAddr:        "",
		Timeout:          5 * time.Second,
		RetryCount:       3,
		RetryInterval:    1 * time.Second,
		AutoSequence:     true,
		ProtocolFactory:  common.NewDefaultProtocolFactory(),
		MaxConnections:   10,
		ConnectionTTL:    30 * time.Second,
		KeepAlive:        true,
	}
}

// HardwareClient 硬件通信客户端 - 适配器模式
type HardwareClient struct {
	config       *HardwareClientConfig
	conn         *net.UDPConn
	serverAddr   *net.UDPAddr
	mu           sync.RWMutex
	closed       bool
	sequence     uint64 // 原子操作的序列号
	
	// 统计信息
	stats        ClientStats
}

// ClientStats 客户端统计信息
type ClientStats struct {
	TotalSent     uint64 // 总发送数
	TotalReceived uint64 // 总接收数
	TotalErrors   uint64 // 总错误数
	LastSentTime  time.Time // 最后发送时间
	LastError     error     // 最后错误
}

// NewHardwareClient 创建新的硬件客户端
func NewHardwareClient(config *HardwareClientConfig) (*HardwareClient, error) {
	if config == nil {
		return nil, fmt.Errorf("配置不能为空")
	}
	
	// 解析服务器地址
	serverAddr, err := net.ResolveUDPAddr("udp", config.ServerAddr)
	if err != nil {
		return nil, fmt.Errorf("解析服务器地址失败 %s: %w", config.ServerAddr, err)
	}
	
	client := &HardwareClient{
		config:     config,
		serverAddr: serverAddr,
		sequence:   0,
	}
	
	return client, nil
}

// Connect 建立连接
func (c *HardwareClient) Connect() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	
	if c.conn != nil && !c.closed {
		return nil // 已经连接
	}
	
	var localAddr *net.UDPAddr
	var err error
	
	// 如果指定了本地地址，则解析它
	if c.config.LocalAddr != "" {
		localAddr, err = net.ResolveUDPAddr("udp", c.config.LocalAddr)
		if err != nil {
			return fmt.Errorf("解析本地地址失败 %s: %w", c.config.LocalAddr, err)
		}
	}
	
	// 创建UDP连接
	c.conn, err = net.DialUDP("udp", localAddr, c.serverAddr)
	if err != nil {
		return fmt.Errorf("建立UDP连接失败 %s: %w", c.serverAddr, err)
	}
	
	c.closed = false
	return nil
}

// Close 关闭连接
func (c *HardwareClient) Close() error {
	c.mu.Lock()
	defer c.mu.Unlock()
	
	if c.conn == nil || c.closed {
		return nil
	}
	
	c.closed = true
	return c.conn.Close()
}

// SendProtocol 发送协议数据包
func (c *HardwareClient) SendProtocol(protocol common.Protocol) error {
	// 自动设置序列号
	if c.config.AutoSequence {
		seq := atomic.AddUint64(&c.sequence, 1)
		protocol.SetSequence(uint16(seq))
	}
	
	// 验证协议
	if err := protocol.Validate(); err != nil {
		atomic.AddUint64(&c.stats.TotalErrors, 1)
		c.stats.LastError = err
		return fmt.Errorf("协议验证失败: %w", err)
	}
	
	return c.sendRawProtocol(protocol)
}

// SendProtocolWithResponse 发送协议并等待响应
func (c *HardwareClient) SendProtocolWithResponse(protocol common.Protocol) (common.Protocol, error) {
	ctx, cancel := context.WithTimeout(context.Background(), c.config.Timeout)
	defer cancel()
	
	return c.SendProtocolWithResponseContext(ctx, protocol)
}

// SendProtocolWithResponseContext 发送协议并等待响应（带上下文）
func (c *HardwareClient) SendProtocolWithResponseContext(ctx context.Context, proto common.Protocol) (common.Protocol, error) {
	var lastErr error
	
	// 重试机制
	for i := 0; i <= c.config.RetryCount; i++ {
		if i > 0 {
			// 等待重试间隔
			select {
			case <-ctx.Done():
				return nil, ctx.Err()
			case <-time.After(c.config.RetryInterval):
			}
		}
		
		// 自动设置序列号
		if c.config.AutoSequence {
			seq := atomic.AddUint64(&c.sequence, 1)
			proto.SetSequence(uint16(seq))
		}
		
		// 验证协议
		if err := proto.Validate(); err != nil {
			lastErr = fmt.Errorf("协议验证失败 (尝试 %d/%d): %w", i+1, c.config.RetryCount+1, err)
			atomic.AddUint64(&c.stats.TotalErrors, 1)
			c.stats.LastError = err
			continue
		}
		
		// 发送协议
		if err := c.sendRawProtocol(proto); err != nil {
			lastErr = fmt.Errorf("发送失败 (尝试 %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		// 等待响应
		response, err := c.receiveProtocolWithContext(ctx)
		if err != nil {
			lastErr = fmt.Errorf("接收失败 (尝试 %d/%d): %w", i+1, c.config.RetryCount+1, err)
			continue
		}
		
		return response, nil
	}
	
	return nil, fmt.Errorf("所有重试尝试失败: %w", lastErr)
}

// sendRawProtocol 发送原始协议数据包
func (c *HardwareClient) sendRawProtocol(proto common.Protocol) error {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return fmt.Errorf("连接未建立")
	}
	
	if c.closed {
		return ErrConnectionClosed
	}
	
	data := proto.Marshal()
	
	// 设置写超时
	if err := c.conn.SetWriteDeadline(time.Now().Add(c.config.Timeout)); err != nil {
		return fmt.Errorf("设置写超时失败: %w", err)
	}
	
	n, err := c.conn.Write(data)
	if err != nil {
		atomic.AddUint64(&c.stats.TotalErrors, 1)
		c.stats.LastError = err
		return fmt.Errorf("写入数据失败: %w", err)
	}
	
	if n != len(data) {
		err := fmt.Errorf("写入不完整: 写入 %d 字节, 期望 %d", n, len(data))
		atomic.AddUint64(&c.stats.TotalErrors, 1)
		c.stats.LastError = err
		return err
	}
	
	// 更新统计信息
	atomic.AddUint64(&c.stats.TotalSent, 1)
	c.stats.LastSentTime = time.Now()
	
	return nil
}

// receiveProtocolWithContext 接收协议数据包（带上下文）
func (c *HardwareClient) receiveProtocolWithContext(ctx context.Context) (common.Protocol, error) {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return nil, fmt.Errorf("连接未建立")
	}
	
	if c.closed {
		return nil, ErrConnectionClosed
	}
	
	// 创建一个channel来接收结果
	type result struct {
		protocol common.Protocol
		err      error
	}
	
	resultCh := make(chan result, 1)
	
	go func() {
		// 设置读超时
		deadline, ok := ctx.Deadline()
		if ok {
			if err := c.conn.SetReadDeadline(deadline); err != nil {
				resultCh <- result{nil, fmt.Errorf("设置读超时失败: %w", err)}
				return
			}
		}
		
		// 读取数据
		buffer := make([]byte, 2048) // 增大缓冲区以支持更大的协议包
		n, err := c.conn.Read(buffer)
		if err != nil {
			resultCh <- result{nil, fmt.Errorf("读取数据失败: %w", err)}
			return
		}
		
		// 解析协议
		proto, err := c.config.ProtocolFactory.ParseProtocol(buffer[:n])
		if err != nil {
			resultCh <- result{nil, fmt.Errorf("解析协议失败: %w", err)}
			return
		}
		
		resultCh <- result{proto, nil}
	}()
	
	// 等待结果或上下文取消
	select {
	case res := <-resultCh:
		if res.err == nil {
			atomic.AddUint64(&c.stats.TotalReceived, 1)
		} else {
			atomic.AddUint64(&c.stats.TotalErrors, 1)
			c.stats.LastError = res.err
		}
		return res.protocol, res.err
	case <-ctx.Done():
		return nil, ctx.Err()
	}
}

// 便捷方法

// SendText 发送文本协议
func (c *HardwareClient) SendText(text string, x, y uint32) error {
	builder := text.NewBuilder()
	proto, err := builder.
		SetText(text).
		SetPosition(x, y).
		SetFontName("Arial").
		SetFontSize(16).
		SetFontWidth(16).
		Build()
	if err != nil {
		return fmt.Errorf("构建文本协议失败: %w", err)
	}
	
	return c.SendProtocol(proto)
}

// SendBarcode 发送条码协议
func (c *HardwareClient) SendBarcode(text string, barcodeType barcode.Type, x, y, width, height uint32) error {
	builder := barcode.NewBuilder()
	proto, err := builder.
		SetText(text).
		SetBarcodeType(barcodeType).
		SetPosition(x, y).
		SetSize(width, height).
		Build()
	if err != nil {
		return fmt.Errorf("构建条码协议失败: %w", err)
	}
	
	return c.SendProtocol(proto)
}

// 状态查询方法

// IsConnected 检查连接状态
func (c *HardwareClient) IsConnected() bool {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	return c.conn != nil && !c.closed
}

// GetServerAddr 获取服务器地址
func (c *HardwareClient) GetServerAddr() string {
	return c.config.ServerAddr
}

// GetLocalAddr 获取本地地址
func (c *HardwareClient) GetLocalAddr() string {
	c.mu.RLock()
	defer c.mu.RUnlock()
	
	if c.conn == nil {
		return ""
	}
	
	return c.conn.LocalAddr().String()
}

// GetStats 获取统计信息
func (c *HardwareClient) GetStats() ClientStats {
	return ClientStats{
		TotalSent:     atomic.LoadUint64(&c.stats.TotalSent),
		TotalReceived: atomic.LoadUint64(&c.stats.TotalReceived),
		TotalErrors:   atomic.LoadUint64(&c.stats.TotalErrors),
		LastSentTime:  c.stats.LastSentTime,
		LastError:     c.stats.LastError,
	}
}

// ResetStats 重置统计信息
func (c *HardwareClient) ResetStats() {
	atomic.StoreUint64(&c.stats.TotalSent, 0)
	atomic.StoreUint64(&c.stats.TotalReceived, 0)
	atomic.StoreUint64(&c.stats.TotalErrors, 0)
	c.stats.LastSentTime = time.Time{}
	c.stats.LastError = nil
}

// GetNextSequence 获取下一个序列号
func (c *HardwareClient) GetNextSequence() uint16 {
	seq := atomic.AddUint64(&c.sequence, 1)
	return uint16(seq)
}

// SetSequence 设置序列号
func (c *HardwareClient) SetSequence(seq uint16) {
	atomic.StoreUint64(&c.sequence, uint64(seq))
}